package com.classroommanagesystem.security;

import com.classroommanagesystem.common.Result;
import com.classroommanagesystem.intercepts.JwtAuthenticationFilter;
import com.classroommanagesystem.utils.ErrorResponseUtil;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

/**
 * @author victory
 * @date 2025/10/24 21:48
 */
@Configuration
@EnableWebSecurity
@EnableMethodSecurity // 开启方法级权限控制（支持@PreAuthorize）
@Slf4j
public class SecurityConfig {
    @Autowired
    private CustomUserDetailsService customUserDetailsService;

    // 配置密码加密器
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    // 注入JWT认证过滤器
    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() {
        return new JwtAuthenticationFilter();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .cors(cors -> cors.configurationSource(corsConfigurationSource())) // 开启跨域配置
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 关闭session创建（使用JWT，无需Session）
                .authorizeHttpRequests(auth -> auth
                        // 放行公共接口（登录注册文件上传等）Swagger相关所有路径
                        .requestMatchers("/static/**", "/public/**", "/doc.html", "/swagger-ui/**", "/swagger-ui.html", "/v3/api-docs/**", "/webjars/**").permitAll()
                        .requestMatchers("/superadmin/**").hasAuthority(RoleConstant.ROLE_SUPERADMIN)
                        .requestMatchers("/admin/**").hasAnyAuthority(RoleConstant.ROLE_SUPERADMIN, RoleConstant.ROLE_ADMIN)
                        .requestMatchers("/user/**").hasAnyAuthority(RoleConstant.ROLE_SUPERADMIN, RoleConstant.ROLE_ADMIN, RoleConstant.ROLE_USER)
                        .anyRequest().authenticated() // 其他所有请求都需要认证
                )
                .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) // 添加JWT认证过滤器
                .csrf(AbstractHttpConfigurer::disable) // 关闭CSRF保护（JWT无需CSRF令牌）
                .userDetailsService(customUserDetailsService)
                .exceptionHandling(exception -> exception
                        // 配置权限不足时的处理器
                        .accessDeniedHandler((request, response, accessDeniedException) -> {
                            ErrorResponseUtil.write(response, "权限不足");
                        })
                        // 时配置未认证（未登录）时的处理器
                        .authenticationEntryPoint((request, response, authException) -> {
                            ErrorResponseUtil.write(response, "未登录");
                        })
                );
        return http.build();
    }

    // 定义跨域配置规则
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        // 创建跨域配置对象
        CorsConfiguration config = new CorsConfiguration();
        // 允许的前端域名（生产环境需指定具体域名，如"http://localhost:8080"）
        config.addAllowedOriginPattern("*"); // 开发环境用*，生产环境替换为具体域名
        // 允许的请求头（包含自定义头，如Authorization）
        config.addAllowedHeader("*");
        // 允许的请求方法（GET/POST/PUT/DELETE等）
        config.addAllowedMethod("*");
        // 允许前端携带Cookie（如需前后端共享cookie需开启）
        config.setAllowCredentials(true);
        // 预检请求的有效期（秒），避免频繁预检
        config.setMaxAge(3600L);

        // 应用到所有路径
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }

}
